//
//  Contact+Extension.swift
//  reader
//
//  Created by shuguan wang on 2017/4/24.
//  Copyright © 2017年 shuguan wang. All rights reserved.
//

import Foundation
import Contacts
import AddressBook
import UIKit
import SwiftyJSON
public enum ZWTContactKeys:UInt {
    //name
    case firstName,middleName,lastName,name
    case nickName,phoneticFamilyName,phoneticMiddleName,phoneticFirstName
    case organization,department,jobTitle
    case tels,emails
    case image
    @available(iOS 9.0, *)
    static var keyToPath:[CNKeyDescriptor] = [CNContactFamilyNameKey as CNKeyDescriptor,
                                              CNContactGivenNameKey as CNKeyDescriptor,
                                              CNContactMiddleNameKey as CNKeyDescriptor,
                                              
                                              CNContactNicknameKey as CNKeyDescriptor,
                                              CNContactOrganizationNameKey as CNKeyDescriptor,
                                              CNContactDepartmentNameKey as CNKeyDescriptor,
                                              CNContactJobTitleKey as CNKeyDescriptor,
                                              
                                              CNContactPhoneticGivenNameKey as CNKeyDescriptor,
                                              CNContactPhoneticMiddleNameKey as CNKeyDescriptor,
                                              CNContactPhoneticFamilyNameKey as CNKeyDescriptor,
                                              
                                              CNContactPhoneNumbersKey as CNKeyDescriptor,
                                              CNContactEmailAddressesKey as CNKeyDescriptor,
                                              CNContactThumbnailImageDataKey as CNKeyDescriptor]
    var desciption:String {
        get{
            switch self {
            case .firstName:
                return "firstName"
            case .middleName:
                return "middleName"
            case .nickName:
                return "nickName"
            case .lastName:
                return "lastName"
            case .name:
                return "name"
            case .phoneticFamilyName:
                return "phoneticFamilyName"
            case .phoneticMiddleName:
                return "phoneticMiddleName"
            case .phoneticFirstName:
                return "phoneticFirstName"
            case .organization:
                return "organization"
            case .department:
                return "department"
            case .jobTitle:
                return "jobTitle"
            case .tels:
                return "tels"
            case .image:
                return "image"
            default:
                return "emails"
            }
        }
    }
}
public protocol ZWTContactMethods{
    func requestLocalContacts(authorizedAction:@escaping ((ZWTContactMethods)->Void),notDeterminedAction:@escaping ((ZWTContactMethods)->Void),deniedAction:@escaping ((ZWTContactMethods)->Void))->Self
    func requestAccess(completion:@escaping (Bool, Error?)->Void)
    func getAllContacts()->[[ZWTContactKeys:Any]]
    func getAllJSONContacts()->[JSON]
    func saveContact(json:JSON) -> Bool
    func isExist(json:JSON)->Bool
    
}
extension Dictionary {
    init<S: Sequence>(_ seq: S) where S.Iterator.Element == Element {
        self.init()
        for (k,v) in seq {
            self[k] = v
        }
    }
}

public func requestLocalContacts(authorizedAction:@escaping ((ZWTContactMethods)->Void)={_ in },notDeterminedAction:@escaping ((ZWTContactMethods)->Void)={_ in },deniedAction:@escaping ((ZWTContactMethods)->Void)={_ in })->ZWTContactMethods?{
    if #available(iOS 9.0, *) {
        return CNContactStore().requestLocalContacts(authorizedAction: authorizedAction, notDeterminedAction: notDeterminedAction, deniedAction: deniedAction)
    } else {
        // Fallback on earlier versions
//        if let addressbook = ABAddressBookCreate(){
//            return addressbook.requestLocalContacts(authorizedAction: authorizedAction, notDeterminedAction: notDeterminedAction, deniedAction: deniedAction)
//        }
        return nil
    }
}
@available(iOS 9.0, *)
extension CNContactStore:ZWTContactMethods{
    public func isExist(json: JSON) -> Bool {
        var isexist = false
        let array = getAllJSONContacts()
        for contact in array {
            let tels = contact["tels"].arrayValue
            for dic in tels {
                if dic.dictionaryValue.first?.value.stringValue == json["mobile"].stringValue {
                    isexist = true
                    return isexist
                }
            }
        }
        return isexist
    }

    
    public func saveContact(json: JSON)->Bool {
        let contact = CNMutableContact()
        contact.givenName = json["name"].stringValue
        var arry = [CNLabeledValue(
            label:CNLabelPhoneNumberMobile,
            value:CNPhoneNumber(stringValue:json["mobile"].stringValue))]
        if !json["tel"].stringValue.isEmpty {
            arry.append(CNLabeledValue.init(label: "座机", value: CNPhoneNumber(stringValue:json["tel"].stringValue)))
        }
        if !json["tel1"].stringValue.isEmpty {
            arry.append(CNLabeledValue.init(label: "电话", value: CNPhoneNumber(stringValue:json["tel1"].stringValue)))
        }
        
        contact.phoneNumbers = arry
        contact.departmentName = json["deptName"].stringValue
        contact.jobTitle = json["position"].stringValue
        contact.organizationName = json["book_name"].stringValue
        contact.emailAddresses = [CNLabeledValue(label: CNLabelEmailiCloud, value: NSString(string:json["email"].stringValue))]
        let saveRequest = CNSaveRequest()
        saveRequest.add(contact, toContainerWithIdentifier:nil)
        var isSuccess = true
        do {
            try execute(saveRequest)
        } catch {
            isSuccess = false
            ZWTPrint(error)
        }
        return isSuccess
    }

    public func getAllJSONContacts() -> [JSON] {
        let cc = getAllContacts().map { (obj: [ZWTContactKeys : Any]) -> JSON in
            var dic:[String:Any] = [:]
            for (k,v) in obj{
                dic[k.desciption] = v
            }
            return JSON(dic)
        }
        return cc
    }

    public func getAllContacts() -> [[ZWTContactKeys:Any]] {
        var jsons:[[ZWTContactKeys:Any]] = []
        do{
            let keys:[CNKeyDescriptor] = ZWTContactKeys.keyToPath
            try enumerateContacts(with: CNContactFetchRequest(keysToFetch: keys), usingBlock: { (c, b) in
                var dic:[ZWTContactKeys:Any] = [:]
                var displayName = ""
                if c.thumbnailImageData != nil{
                    dic[ZWTContactKeys.image] = c.thumbnailImageData?.base64EncodedString()
                }
                if !c.familyName.isEmpty{
                    dic[ZWTContactKeys.lastName] = c.familyName
                    displayName.append(c.familyName)
                }
                if !c.middleName.isEmpty{
                    dic[ZWTContactKeys.middleName] = c.middleName
                    displayName.append(c.middleName)
                }
                if !c.givenName.isEmpty{
                    dic[ZWTContactKeys.firstName] = c.givenName
                    displayName.append(c.givenName)
                }
                
                var tempDisplayName = displayName
                if !c.phoneticFamilyName.isEmpty{
                    dic[ZWTContactKeys.phoneticFamilyName] = c.phoneticFamilyName
                    if tempDisplayName.isEmpty {
                        displayName.append(c.phoneticFamilyName)
                    }
                }
                if !c.phoneticMiddleName.isEmpty{
                    dic[ZWTContactKeys.phoneticMiddleName] = c.phoneticMiddleName
                    if tempDisplayName.isEmpty {
                        displayName.append(c.phoneticMiddleName)
                    }
                }
                if !c.phoneticGivenName.isEmpty{
                    dic[ZWTContactKeys.phoneticFirstName] = c.phoneticGivenName
                    if tempDisplayName.isEmpty {
                        displayName.append(c.phoneticGivenName)
                    }
                }
                
                tempDisplayName = displayName
                if !c.nickname.isEmpty{
                    dic[ZWTContactKeys.nickName] = c.nickname
                    if tempDisplayName.isEmpty {
                        displayName.append(c.nickname)
                    }
                }
                tempDisplayName = displayName
                if !c.organizationName.isEmpty{
                    dic[ZWTContactKeys.organization] = c.organizationName
                    if tempDisplayName.isEmpty {
                        displayName.append(c.organizationName)
                    }
                }
                tempDisplayName = displayName
                if !c.departmentName.isEmpty{
                    dic[ZWTContactKeys.department] = c.departmentName
                    if tempDisplayName.isEmpty {
                        displayName.append(c.departmentName)
                    }
                }
                tempDisplayName = displayName
                if !c.jobTitle.isEmpty{
                    dic[ZWTContactKeys.jobTitle] = c.jobTitle
                    if tempDisplayName.isEmpty {
                        displayName.append(c.jobTitle)
                    }
                }
                tempDisplayName = displayName
                var numbers:[[String:String]] = []
                for number:CNLabeledValue<CNPhoneNumber> in c.phoneNumbers{
                    var phonenumber = number.value.stringValue.replacingOccurrences(of: "+", with: "").replacingOccurrences(of: "(", with: "").replacingOccurrences(of: ")", with: "").replacingOccurrences(of: "-", with: "").replacingOccurrences(of: " ", with: "").replacingOccurrences(of: " ", with: "")
                    if phonenumber.hasPrefix("86"){
                        phonenumber = phonenumber[2..<phonenumber.count-2]
                    }
                    let label = number.label ?? "电话"
                    numbers.append([CNLabeledValue<CNPhoneNumber>.localizedString(forLabel: label):phonenumber])
                }
                numbers.sort(by: { (obj1, obj2) -> Bool in
                    let str1 = "\(obj1.values.first!)"
                    let str2 = "\(obj2.values.first!)"
                    if str1.count == 11 && str1.hasPrefix("1"){
                        if str2.count == 11 && str2.hasPrefix("1"){
                            return str1<str2
                        }else{
                            return true
                        }
                    }else{
                        return false
                    }
                })
                if !numbers.isEmpty{
                    dic[ZWTContactKeys.tels] = numbers
                    if tempDisplayName.isEmpty && !numbers.isEmpty {
                        displayName.append((numbers.first?.values.first)!)
                    }
                }
                tempDisplayName = displayName
                let emails = c.emailAddresses.map({ (email:CNLabeledValue<NSString>) -> String in
                    return email.value as String
                })
                if !emails.isEmpty{
                    dic[ZWTContactKeys.emails] = emails
                    if tempDisplayName.isEmpty && !emails.isEmpty {
                        displayName.append(emails.first!)
                    }
                }
                dic[ZWTContactKeys.name] = displayName
                jsons.append(dic)
            })
        }catch{
            
        }
        return jsons
    }

    public func requestLocalContacts(authorizedAction: @escaping ((ZWTContactMethods) -> Void), notDeterminedAction: @escaping ((ZWTContactMethods) -> Void), deniedAction: @escaping ((ZWTContactMethods) -> Void)) -> Self {
        
        switch CNContactStore.authorizationStatus(for: .contacts) {
        case .authorized:
            authorizedAction(self)
        case .notDetermined:
            notDeterminedAction(self)
        default:
            deniedAction(self)
        }
        return self
    }

    public func requestAccess(completion: @escaping (Bool, Error?) -> Void) {
        self.requestAccess(for: .contacts, completionHandler: completion)
    }
}
//extension Unmanaged:ZWTContactMethods{
//    public func isExist(json: JSON) -> Bool {
//        return false
//    }
//
//    public func saveContact(json: JSON) -> Bool {
//        let contact = ABPersonCreate() as ABRecord
//        ABRecordSetValue(contact, kABPersonFirstNamePhoneticProperty, json["name"].stringValue as CFTypeRef, nil)
//        ABRecordSetValue(contact, kABPersonPhoneProperty, json["mobile"].stringValue as CFTypeRef, nil)
//        let addressBook:ABAddressBook = ((self as ABAddressBook) as! Unmanaged<ABAddressBook>).takeRetainedValue() as ABAddressBook
//        if ABAddressBookAddRecord(addressBook, contact as ABRecord, nil) {
//            if ABAddressBookSave(addressBook, nil) {
//               return true
//            }
//        }
//        return false
//    }
//
//
//    public func getAllJSONContacts() -> [JSON] {
//        let cc = getAllContacts().map { (obj: [ZWTContactKeys : Any]) -> JSON in
//            var dic:[String:Any] = [:]
//            for (k,v) in obj{
//                dic[k.desciption] = v
//            }
//            return JSON(dic)
//        }
//        return cc
//    }
//
//    public func getAllContacts() -> [[ZWTContactKeys:Any]] {
//        var jsons:[[ZWTContactKeys:Any]] = []
//        let o:ABAddressBook = ((self as ABAddressBook) as! Unmanaged<ABAddressBook>).takeRetainedValue() as ABAddressBook
//        if let cc = ABAddressBookCopyArrayOfAllPeople(o){
//            let cc1 = cc.takeUnretainedValue() as [ABRecord]
//            for contact in cc1 {
//                var dic:[ZWTContactKeys:Any] = [:]
//                var displayName = ""
//
//                if ABPersonHasImageData(contact),let imagedata = ABPersonCopyImageDataWithFormat(contact, kABPersonImageFormatThumbnail){
//                    dic[ZWTContactKeys.image] = (imagedata.takeUnretainedValue() as Data).base64EncodedString()
//                }
//                if let name =  ABRecordCopyValue(contact, kABPersonLastNameProperty){
//                    let n =  name.takeUnretainedValue() as? String
//                    dic[ZWTContactKeys.lastName] = n
//                    displayName.append(n!)
//                }
//                if let name =  ABRecordCopyValue(contact, kABPersonMiddleNameProperty){
//                    let n =  name.takeUnretainedValue() as? String
//                    dic[ZWTContactKeys.middleName] = n
//                    displayName.append(n!)
//                }
//                if let name =  ABRecordCopyValue(contact, kABPersonFirstNameProperty){
//                    let n =  name.takeUnretainedValue() as? String
//                    dic[ZWTContactKeys.firstName] = n
//                    displayName.append(n!)
//                }
//                var tempDisplayName = displayName
//                if let name =  ABRecordCopyValue(contact, kABPersonLastNamePhoneticProperty){
//                    let n =  name.takeUnretainedValue() as? String
//                    dic[ZWTContactKeys.phoneticFamilyName] = n
//                    if tempDisplayName.isEmpty {
//                        displayName.append(n!)
//                    }
//                }
//                if let name =  ABRecordCopyValue(contact, kABPersonMiddleNamePhoneticProperty){
//                    let n =  name.takeUnretainedValue() as? String
//                    dic[ZWTContactKeys.phoneticMiddleName] = n
//                    if tempDisplayName.isEmpty {
//                        displayName.append(n!)
//                    }
//                }
//                if let name =  ABRecordCopyValue(contact, kABPersonFirstNamePhoneticProperty){
//                    let n =  name.takeUnretainedValue() as? String
//                    dic[ZWTContactKeys.phoneticFirstName] = n
//                    if tempDisplayName.isEmpty {
//                        displayName.append(n!)
//                    }
//                }
//                tempDisplayName = displayName
//                if let name =  ABRecordCopyValue(contact, kABPersonNicknameProperty){
//                    let n =  name.takeUnretainedValue() as? String
//                    dic[ZWTContactKeys.nickName] = n
//                    if tempDisplayName.isEmpty {
//                        displayName.append(n!)
//                    }
//                }
//                tempDisplayName = displayName
//                if let name =  ABRecordCopyValue(contact, kABPersonOrganizationProperty){
//                    let n =  name.takeUnretainedValue() as? String
//                    dic[ZWTContactKeys.organization] = n
//                    if tempDisplayName.isEmpty {
//                        displayName.append(n!)
//                    }
//                }
//                tempDisplayName = displayName
//                if let name =  ABRecordCopyValue(contact, kABPersonDepartmentProperty){
//                    let n =  name.takeUnretainedValue() as? String
//                    dic[ZWTContactKeys.department] = n
//                    if tempDisplayName.isEmpty {
//                        displayName.append(n!)
//                    }
//                }
//                tempDisplayName = displayName
//                if let name =  ABRecordCopyValue(contact, kABPersonJobTitleProperty){
//                    let n =  name.takeUnretainedValue() as? String
//                    dic[ZWTContactKeys.jobTitle] = n
//                    if tempDisplayName.isEmpty {
//                        displayName.append(n!)
//                    }
//                }
//                tempDisplayName = displayName
//                if let values = ABRecordCopyValue(contact, kABPersonPhoneProperty),ABMultiValueGetCount(values.takeUnretainedValue() as ABMultiValue)>0{
//                    var numbers:[[String:String]] = []
//                    for i in 0..<ABMultiValueGetCount(values.takeUnretainedValue() as ABMultiValue){
//                        let keyOrigin = ABMultiValueCopyLabelAtIndex(values.takeUnretainedValue() as ABMultiValue, i).takeUnretainedValue()
//                        var key:String = ABAddressBookCopyLocalizedLabel(keyOrigin).takeUnretainedValue() as String
//                        if key.isEmpty {
//                            key = "电话"
//                        }
//                        let value:String = ABMultiValueCopyValueAtIndex(values.takeUnretainedValue() as ABMultiValue, i).takeUnretainedValue() as! String
//                        //这里替换了两种空白字符串……居然看起来一样，其实是两种，ffffuck
//                        var phonenumber = value.replacingOccurrences(of: "+", with: "").replacingOccurrences(of: "(", with: "").replacingOccurrences(of: ")", with: "").replacingOccurrences(of: "-", with: "").replacingOccurrences(of: " ", with: "").replacingOccurrences(of: " ", with: "")
//                        if phonenumber.hasPrefix("86"){
//                            phonenumber = phonenumber[2..<phonenumber.count-2]
//                        }
//                        numbers.append([key:phonenumber])
//
//
//                    }
//                    numbers.sort(by: { (obj1, obj2) -> Bool in
//                        let str1 = "\(obj1.values.first!)"
//                        let str2 = "\(obj2.values.first!)"
//                        if str1.count == 11 && str1.hasPrefix("1"){
//                            if str2.count == 11 && str2.hasPrefix("1"){
//                                return str1<str2
//                            }else{
//                                return true
//                            }
//                        }else{
//                            return false
//                        }
//                    })
//                    dic[ZWTContactKeys.tels] = numbers
//                    if tempDisplayName.isEmpty && !numbers.isEmpty {
//                        displayName.append((numbers.first?.values.first)!)
//                    }
//                }
//                tempDisplayName = displayName
//                if let values = ABRecordCopyValue(contact, kABPersonEmailProperty),let vs1 = ABMultiValueCopyArrayOfAllValues(values.takeUnretainedValue() as ABMultiValue){
//                    let vs = vs1.takeUnretainedValue() as! [String]
//                    dic[ZWTContactKeys.emails] = vs
//                    if tempDisplayName.isEmpty && !vs.isEmpty {
//                        displayName.append(vs.first!)
//                    }
//                }
//                dic[ZWTContactKeys.name] = displayName
//                jsons.append(dic)
//            }
//        }
//        return jsons
//    }
//
//    public func requestLocalContacts(authorizedAction: @escaping ((ZWTContactMethods) -> Void), notDeterminedAction: @escaping ((ZWTContactMethods) -> Void), deniedAction: @escaping ((ZWTContactMethods) -> Void)) -> Unmanaged<Instance> {
//        ABAddressBookRequestAccessWithCompletion(self as ABAddressBook) { (granted, error) in
//            if granted{
//                authorizedAction(self)
//            }else{
//                deniedAction(self)
//            }
//        }
//        return self
//    }
//    public func requestAccess(completion: @escaping (Bool, Error?) -> Void) {
//        ABAddressBookRequestAccessWithCompletion(self as ABAddressBook) { (status, error) in
//            completion(status, error)
//        }
//    }
//}

